package com.xinyue.game.logic.frame.channel;

import java.util.Collection;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.mygame.common.utils.TopicUtil;
import com.xinyue.mqsystem.mq.GameMQTemplate;
import com.xinyue.network.message.stream.IGameMessage;
import com.xinyue.network.message.stream.ServiceMessageHeader;

import io.netty.buffer.ByteBuf;
import io.netty.util.concurrent.EventExecutor;

public class GameChannel {
    // 绑定一个执行任务的线程池
    private EventExecutor executor;
    private String channelId;
    private Object cacheData;
    private GameMQTemplate mqTemplate;
    private NacosDiscoveryProperties nacosDiscoveryProperties;
    private static final String GatewayTopicPrefix = "XinyueBusinessTopic";

    private static Logger logger = LoggerFactory.getLogger(GameChannel.class);

    public GameChannel(ApplicationContext springContext, EventExecutor executor, String channelId) {
        this.executor = executor;
        this.channelId = channelId;
        mqTemplate = springContext.getBean(GameMQTemplate.class);
        nacosDiscoveryProperties = springContext.getBean(NacosDiscoveryProperties.class);
    }

    /**
     * 向网关发送消息
     * 
     * @param gameMessage
     */
    public void sendToGateway(IGameMessage gameMessage) {
        ByteBuf byteBuf = gameMessage.write();
        ServiceMessageHeader header = (ServiceMessageHeader)gameMessage.getHeader();
        long playerId = header.getPlayerId();
        byte[] data = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(data);
        try {
            String gatewayTopic = TopicUtil.generateTopic(nacosDiscoveryProperties.getNamespace(),GatewayTopicPrefix, header.getToGameModuleInstanceId());
            logger.debug("gatewayToic:{}", gatewayTopic);
            mqTemplate.syncSendOrderly(gatewayTopic, data, playerId);
            if(logger.isDebugEnabled()) {
            	logger.debug(gameMessage.toString());
            }
        } catch (Exception e) {
            logger.error("向网关返回消息失败", e);
        }
    }
    //广播给网关的消息应该使用推送
    public void broadcastToGateway(IGameMessage gameMessage, Collection<Long> playerIds) {
//        ByteBuf byteBuf = gameMessage.write();
//        ServiceMessageHeader header = (ServiceMessageHeader)gameMessage.getHeader();
//        byte[] data = new byte[byteBuf.readableBytes()];
//        byteBuf.readBytes(data);
//        for (Long playerId : playerIds) {
//            byte[] data;
//            try {
//                header = gameMessage.getHeader().clone();
//                header.setPlayerId(playerId.longValue());
//                //如果是广播消息，发送到固定的网关topic，这样所有的网关都会收到这个消息，然后判断玩家是否连接的这个网关，如果不是，则丢弃消息
//                String gatewayTopic = nacosDiscoveryProperties.getNamespace() + "-" + serverConfig.getGatewayGameMessageTopic();
//                logger.debug("gatewayToic:{}", gatewayTopic);
//                data = GameMessageInnerCodec.encodeMessage(header, byteBuf);
//                mqTemplate.syncSendOrderly(gatewayTopic, data, playerId);
//            } catch (Exception e) {
//
//                logger.error("广播消息异常", e);
//            }
//        }
    }

    /**
     * 添加一个延时执行的任务
     * 
     * @param task
     * @param taskName
     * @param delay
     * @param unit
     */
    public void addScheduleTask(Runnable task, String taskName, long delay, TimeUnit unit) {
        executor.schedule(() -> {
            try {
                task.run();
            } catch (Throwable e) {
                logger.error(" channelId:{} {} 延时任务执行失败", channelId, taskName, e);
            }
        }, delay, unit);
    }

    /**
     * 
     * @Desc 添加固定周期执行的任务，是以上一个任务开始的时间计时，period时间过去后，<br/>
     *       检测上一个任务是否执行完毕，如果上一个任务执行完毕，则当前任务立即执行，<br/>
     *       如果上一个任务没有执行完毕，则需要等上一个任务执行完毕后立即执行
     * @Author wang guang shuai
     * @Date 2020年2月17日 下午1:25:11
     * @param task
     * @param taskName
     * @param delay
     * @param period
     * @param unit
     */
    public void addFixedRateScheduleTask(Runnable task, String taskName, long delay, long period, TimeUnit unit) {
        executor.scheduleAtFixedRate(() -> {
            try {
                task.run();
            } catch (Throwable e) {
                logger.error(" channelId:{} {} FixedRate定时任务执行失败", channelId, taskName, e);
            }
        }, delay, period, unit);
    }

    /**
     * 
     * @Desc 添加定时任务，任务是以上一个任务结束时开始计时，period时间过去后，立即执行
     * @Author wang guang shuai
     * @Date 2020年2月17日 下午1:35:06
     * @param task
     * @param taskName
     * @param delay
     * @param period
     * @param unit
     */
    public void addWithFixedDelayScheduleTask(Runnable task, String taskName, long delay, long period, TimeUnit unit) {
        executor.scheduleWithFixedDelay(() -> {
            try {
                task.run();
            } catch (Throwable e) {
                logger.error(" channelId:{} {} WithFixedDelay任务执行失败", channelId, taskName, e);
            }
        }, delay, period, unit);
    }

    public void submitTask(Runnable task, String taskName) {
        executor.execute(() -> {
            try {
                task.run();
            } catch (Throwable e) {
                logger.error(" channelId:{} {} 任务执行失败", channelId, taskName, e);
            }

        });
    }


    public String getChannelId() {
        return channelId;
    }

    public Object getCacheData() {
        return cacheData;
    }

    public void setCacheData(Object cacheData) {
        this.cacheData = cacheData;
    }



}
